package com.renfei.cameralibrary.encoder;

import android.opengl.EGLContext;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;

import com.renfei.filterlibrary.gles.EglCore;
import com.renfei.filterlibrary.gles.WindowSurface;
import com.renfei.filterlibrary.glfilter.base.GLImageFilter;
import com.renfei.filterlibrary.glfilter.utils.OpenGLUtils;
import com.renfei.filterlibrary.glfilter.utils.TextureRotationUtils;

import java.nio.FloatBuffer;

public class RenderHandler implements Runnable {

    private static final boolean DEBUG = false;    // TODO set false on release
    private static final String TAG = "RenderHandler";

    private final Object mSync = new Object();
    private EGLContext mShard_context;
    private Surface mSurface;

    private boolean mRequestSetEglContext;
    private boolean mRequestRelease;
    private int mRequestDraw;

    private int videoWidth;
    private int videoheight;

    private int mTexId = -1;
    private long timestampNanos = 0;


    // 录制用的OpenGL上下文和EGLSurface
    private WindowSurface mInputWindowSurface;
    private EglCore mEglCore;
    private GLImageFilter mImageFilter;
    private FloatBuffer mVertexBuffer;
    private FloatBuffer mTextureBuffer;

    /**
     * 创建的时， RenderHandler.start
     *
     * @param name
     * @return
     */
    public static final RenderHandler createHandler(final String name) {
        if (DEBUG) Log.v(TAG, "createHandler:");
        final RenderHandler handler = new RenderHandler();
        synchronized (handler.mSync) {
            new Thread(handler, !TextUtils.isEmpty(name) ? name : TAG).start();
            try {
                handler.mSync.wait();
            } catch (final InterruptedException e) {
            }
        }
        return handler;
    }

    public final void setEglContext(final EGLContext shared_context, final Surface surface, int width, int height) {
        mVertexBuffer = OpenGLUtils.createFloatBuffer(TextureRotationUtils.CubeVertices);
        mTextureBuffer = OpenGLUtils.createFloatBuffer(TextureRotationUtils.TextureVertices);
        synchronized (mSync) {
            if (mRequestRelease) return;
            mShard_context = shared_context;
            mSurface = surface;

            videoWidth = width;
            videoheight = height;

            mRequestSetEglContext = true;
            mSync.notifyAll();
            try {
                mSync.wait();
            } catch (final InterruptedException e) {
            }
        }
    }

    public void drawFrame(int texture, long timestamp) {
        synchronized (mSync) {
            if (mRequestRelease) return;
            mTexId = texture;
            timestampNanos = timestamp;
            mRequestDraw++;
            mSync.notifyAll();
        }
    }


    public final void release() {
        if (DEBUG) Log.i(TAG, "release:");
        synchronized (mSync) {
            if (mRequestRelease) return;
            mRequestRelease = true;

            if (mImageFilter != null) {
                mImageFilter.release();
                mImageFilter = null;
            }
            if (mInputWindowSurface != null) {
                mInputWindowSurface.release();
                mInputWindowSurface = null;
            }
            if (mEglCore != null) {
                mEglCore.release();
                mEglCore = null;
            }

            mSync.notifyAll();
            try {
                mSync.wait();
            } catch (final InterruptedException e) {
            }
        }
    }

    @Override
    public void run() {
        if (DEBUG) Log.i(TAG, "RenderHandler thread started:");
        synchronized (mSync) {
            mRequestSetEglContext = mRequestRelease = false;
            mRequestDraw = 0;
            mSync.notifyAll();
        }
        boolean localRequestDraw;
        for (; ; ) {
            synchronized (mSync) {
                if (mRequestRelease) break;
                if (mRequestSetEglContext) {
                    mRequestSetEglContext = false;
                    internalPrepare();
                }
                localRequestDraw = mRequestDraw > 0;
                if (localRequestDraw) {
                    mRequestDraw--;
//					mSync.notifyAll();
                }
            }
            if (localRequestDraw) {
                if ((mEglCore != null)) {
                    mInputWindowSurface.makeCurrent();
                    mImageFilter.drawFrame(mTexId, mVertexBuffer, mTextureBuffer);
                    mInputWindowSurface.setPresentationTime(timestampNanos);
                    mInputWindowSurface.swapBuffers();
                }
            } else {
                synchronized (mSync) {
                    try {
                        mSync.wait();
                    } catch (final InterruptedException e) {
                        break;
                    }
                }
            }
        }
        synchronized (mSync) {
            mRequestRelease = true;
            internalRelease();
            mSync.notifyAll();
        }
        if (DEBUG) Log.i(TAG, "RenderHandler thread finished:");
    }

    private final void internalPrepare() {
        if (DEBUG) Log.i(TAG, "internalPrepare:");
        internalRelease();


        // 创建EGL上下文和Surface
        mEglCore = new EglCore(mShard_context, EglCore.FLAG_RECORDABLE);
        mInputWindowSurface = new WindowSurface(mEglCore, mSurface, true);
        mInputWindowSurface.makeCurrent();
        // 创建录制用的滤镜
        mImageFilter = new GLImageFilter(null);
        mImageFilter.onInputSizeChanged(videoWidth, videoheight);
        mImageFilter.onDisplaySizeChanged(videoWidth, videoheight);

        mSurface = null;
        mSync.notifyAll();
    }

    private final void internalRelease() {
        if (DEBUG) Log.i(TAG, "internalRelease:");
        if (mInputWindowSurface != null) {
            mInputWindowSurface.release();
            mInputWindowSurface = null;
        }
        if (mImageFilter != null) {
            mImageFilter.release();
            mImageFilter = null;
        }
        if (mEglCore != null) {
            mEglCore.release();
            mEglCore = null;
        }
    }

}
